/*
 *    Copyright (c) 2018-2025, cloud All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: cloud
 */
package com.fuyao.cloud.asset.receive.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyao.cloud.admin.api.feign.RemoteDeptService;
import com.fuyao.cloud.admin.api.feign.RemoteUserService;
import com.fuyao.cloud.admin.api.vo.UserVO;
import com.fuyao.cloud.asset.card.service.AssetAssetcardService;
import com.fuyao.cloud.asset.constant.AssetConstant;
import com.fuyao.cloud.asset.constant.ReceiveConstant;
import com.fuyao.cloud.asset.dto.receive.*;
import com.fuyao.cloud.asset.entity.AssetCard;
import com.fuyao.cloud.asset.entity.receive.Receive;
import com.fuyao.cloud.asset.entity.receive.ReceiveList;
import com.fuyao.cloud.asset.enums.AssetStatusEnum;
import com.fuyao.cloud.asset.enums.CardStatusEnum;
import com.fuyao.cloud.asset.receive.mapper.ReceiveMapper;
import com.fuyao.cloud.asset.receive.service.ReceiveService;
import com.fuyao.cloud.asset.receivelist.service.ReceiveListService;
import com.fuyao.cloud.common.core.constant.CommonConstants;
import com.fuyao.cloud.common.core.model.BaseEntity;
import com.fuyao.cloud.common.core.util.DictItemOption;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.data.datascope.DataScope;
import com.fuyao.cloud.common.data.resolver.DictItemResolver;
import com.fuyao.cloud.common.data.resolver.NumberResolver;
import com.fuyao.cloud.common.data.resolver.ParamResolver;
import com.fuyao.cloud.common.security.service.CloudUser;
import com.fuyao.cloud.common.security.util.SecurityUtils;
import com.fuyao.cloud.space.entity.RoomHouse;
import com.fuyao.cloud.space.house.service.RoomHouseService;
import com.fuyao.cloud.space.position.service.RoomPositionService;
import com.fuyao.cloud.space.vo.PositionVO;
import lombok.AllArgsConstructor;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 资产领用
 *
 * @author liyue
 * @date 2021-12-16 10:41:00
 */
@Service
@AllArgsConstructor
public class ReceiveServiceImpl extends ServiceImpl<ReceiveMapper, Receive> implements ReceiveService {

	private final ReceiveListService receiveListService;
	private final RemoteDeptService deptService;
	private final RoomHouseService houseService;
	private final RoomPositionService positionService;
	private final RemoteUserService remoteUserService;
	private final AssetAssetcardService assetCardService;

	@Transactional
	@Override
	public boolean save(Receive entity) {
		saveUpdateBefore(entity);
		boolean hasSave = super.save(entity);
		if (hasSave) {
			receiveListService.saveUpdateReceiveList(entity);
		}
		return hasSave;
	}

	@Override
	public boolean updateById(Receive entity) {
		saveUpdateBefore(entity);
		boolean hasUpdate = super.updateById(entity);
		if (hasUpdate) {
			receiveListService.saveUpdateReceiveList(entity);
		}
		return hasUpdate;
	}

	@Override
	public ReceiveCreateDTO create(String type) {
		CloudUser user = SecurityUtils.getUser();
		ReceiveCreateDTO createDTO = new ReceiveCreateDTO();
		createDTO.setStatus(AssetConstant.DEFAULT_STATUS);
		createDTO.setCreateId(user.getId());
		createDTO.setCreateBy(user.getName());
		createDTO.setCreateTime(LocalDateTime.now());
		createDTO.setDeptId(user.getDeptId());
		createDTO.setDeptFullname(user.getFullName());
		createDTO.setUnid(UUID.randomUUID().toString());
		createDTO.setUserId(user.getId());
		createDTO.setUserName(user.getName());
		createDTO.setUserOuid(user.getDeptId());
		createDTO.setUserOufullname(user.getFullName());
		createDTO.setCurrencyType(AssetConstant.DEFAULT_CURRENCY_TYPE);
		createDTO.setType(type);
		createDTO.setDictOption(getDictOption());

		String caseKey = ParamResolver.getStr("RECEIVE_CASE_VALUE", "ARE");
		if(ReceiveConstant.WITHDRAWAL_TYPE.equals(createDTO.getType())){
			caseKey = ParamResolver.getStr("RECEIVE_CASE_VALUE", "ART");
		}
		Map<String, String> numberMap = NumberResolver.getNumberMap(ReceiveConstant.RECEIVE_STATUS, DateUtil.format(new Date(), DatePattern.SIMPLE_MONTH_PATTERN), 5L).getData();
		createDTO.setCaseid(caseKey + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN) + numberMap.get("code"));
		return createDTO;
	}

	@Override
	public ReceiveEditDTO edit(Long id) {
		Receive receive = this.getById(id);
		Assert.isTrue(ObjectUtils.isNotEmpty(receive), String.format("%s不合法", id));
		ReceiveEditDTO editDTO = new ReceiveEditDTO();
		BeanUtil.copyProperties(receive, editDTO);
		List<ReceiveList> receiveList = this.receiveListService.list(Wrappers.<ReceiveList>query().lambda().eq(ReceiveList::getParentId, receive.getId()));
		editDTO.setReceiveList(receiveList);
		editDTO.setDictOption(getDictOption());
		return editDTO;
	}

	@Override
	public List listReceive(QueryWrapper<Receive> query,String type) {
		List<Receive> receiveList = this.list(query);
		Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(ReceiveConstant.RECEIVE_STATUS);
		if (CollUtil.isNotEmpty(receiveList)) {
			if("0".equals(type)){
				return receiveList.stream().map(receive -> {
					ReceiveExcelDTO excelDTO = new ReceiveExcelDTO();
					BeanUtil.copyProperties(receive, excelDTO);
					excelDTO.setStatus(DictItemResolver.getDictOptionLabel(resultMap.get(ReceiveConstant.RECEIVE_STATUS), String.valueOf(receive.getStatus())));
					return excelDTO;
				}).collect(Collectors.toList());
			}else{
				return receiveList.stream().map(receive -> {
					WithdrawalExcelDTO excelDTO = new WithdrawalExcelDTO();
					BeanUtil.copyProperties(receive, excelDTO);
					excelDTO.setStatus(DictItemResolver.getDictOptionLabel(resultMap.get(ReceiveConstant.RECEIVE_STATUS), String.valueOf(receive.getStatus())));
					return excelDTO;
				}).collect(Collectors.toList());
			}
		}
		return Collections.emptyList();
	}

	@Override
	public IPage page(Page page, QueryWrapper queryWrapper, ReceiveSearchDTO receive) {
		queryWrapper.eq("del_flag", 0);
		return this.baseMapper.page(page, queryWrapper, receive,new DataScope());
	}

	@Override
	public R batchDelete(List<Long> ids) {
		List<Receive> receiveList = this.list(Wrappers.<Receive>query().lambda().in(BaseEntity::getId, ids));
		if (CollUtil.isEmpty(receiveList)) {
			return R.failed("未找到相应的（领用/退库）数据");
		}
		CloudUser user = SecurityUtils.getUser();
		boolean allMatch = receiveList.stream().allMatch(receive -> AssetStatusEnum.DRAFT.getCode().equals(receive.getStatus()) && user.getId().equals(receive.getCreateId()));
		if (!allMatch) {
			return R.failed("只能删除草稿状态且创建用户为当前用户的（领用/退库）数据");
		}
		boolean remove = this.receiveListService.remove(Wrappers.<ReceiveList>query().lambda().in(ReceiveList::getParentId, ids));
		boolean delete = this.removeBatchByIds(ids);
		if (!delete && !remove) {
			return R.failed("删除失败，请检查数据有效性");
		}
		return R.ok(CommonConstants.SUCCESS, "删除成功");
	}

	@Override
	public boolean approval(Receive receive) {
		boolean save = this.updateById(receive);

		List<ReceiveList> receiveList = this.receiveListService.list(Wrappers.<ReceiveList>query().lambda().eq(ReceiveList::getParentId, receive.getId()));
		if(save){
			List<Long> ids = receiveList.stream().map(ReceiveList::getAssetCardId).distinct().collect(Collectors.toList());
			List<AssetCard> assetCardList = assetCardService.listByIds(ids);
			List<AssetCard> saveAssetCardList = Lists.newArrayList();
			ids.forEach(assetCardId -> {
				Optional<AssetCard> aessetCardOptional = assetCardList.stream().filter(assetCard -> assetCard.getId().equals(assetCardId)).findFirst();
				if(aessetCardOptional.isPresent()){
					AssetCard assetCard = aessetCardOptional.get();
					// 领用 =>在用 退库=>库存
					String status = (receive.getType().equals(ReceiveConstant.RECEIVE_TYPE) ? CardStatusEnum.USING.getCode() : CardStatusEnum.STOCK.getCode());
					assetCard.setStatus(status);
					assetCard.setUseId(receive.getUserId());
					assetCard.setUseName(receive.getUserName());
					assetCard.setUseDate(receive.getCreateTime().toLocalDate());
					assetCard.setUsedept(receive.getUserOuname());
					assetCard.setUsedeptFullname(receive.getUserOufullname());
					assetCard.setUsedeptId(receive.getUserOuid());
					assetCard.setHouseId(receive.getInhouseId());
					assetCard.setHouseName(receive.getInhouseName());
					assetCard.setLocationId(receive.getInlocationId());
					assetCard.setLocation(receive.getInlocationName());
					assetCard.setParentStorageplace(receive.getInfullLocation());

					saveAssetCardList.add(assetCard);
				}
			});
			// 修改资产使用信息
			return this.assetCardService.saveOrUpdateBatch(saveAssetCardList);
		}
		return save;
	}

	private ReceiveCreateDTO.DictOption getDictOption() {
		ReceiveCreateDTO.DictOption dictOption = new ReceiveCreateDTO.DictOption();
		String[] options = new String[]{ReceiveConstant.RECEIVE_STATUS, AssetConstant.CURRENCY_TYPE};
		Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(options);
		dictOption.setStatusList(resultMap.get(ReceiveConstant.RECEIVE_STATUS));
		dictOption.setCurrencyTypeList(resultMap.get(AssetConstant.CURRENCY_TYPE));
		dictOption.setDeptTreeList(deptService.tree().getData());
		List<Tree<String>> treeList = houseService.selectTree();
		dictOption.setHouseTreeList(treeList);
		List<Tree<String>> warehouseTreeList = houseService.warehouseTree();
		dictOption.setWarehouseTreeList(warehouseTreeList);
		// dictOption.setPositionTreeList(remotePositionService.getPositionTree(new RoomPosition()).getData());
		return dictOption;
	}

	private void saveUpdateBefore(Receive entity) {
		List<ReceiveList> receiveList = entity.getReceiveList();
		if (CollUtil.isNotEmpty(receiveList)) {
			StringBuilder detailed = new StringBuilder();
			receiveList.forEach(p -> detailed.append(p.getName()).append(","));
			detailed.deleteCharAt(detailed.length() - 1);
			// 计算总金额
			long amount = receiveList.stream().collect(Collectors.summarizingLong((ReceiveList::getAmountLong))).getSum();
			entity.setAmount(new BigDecimal(amount));
			entity.setDetailed(detailed.toString());
		}
		// 使用人
		if (ObjectUtils.isNotEmpty(entity.getUserId()) && entity.getUserId() > 0) {
			UserVO userVO = remoteUserService.getUserName(entity.getUserId()).getData();
			entity.setUserOuname(userVO.getDeptName());
			entity.setUserOufullname(StrUtil.emptyToDefault(userVO.getDeptFullName(),userVO.getDeptName()));
		}
		// 存放房间
		if (ObjectUtils.isNotEmpty(entity.getInhouseId()) && entity.getInhouseId() > 0) {
			RoomHouse roomHouse = this.houseService.getById(entity.getInhouseId());
			entity.setInhouseName(roomHouse.getName());
		}
		// 领用仓库
		if (ObjectUtils.isNotEmpty(entity.getOuthouseId()) && entity.getOuthouseId() > 0) {
			RoomHouse roomHouse = this.houseService.getById(entity.getOuthouseId());
			entity.setOuthouseName(roomHouse.getName());
			entity.setFullLocation(roomHouse.getParentFullname()+ "." + roomHouse.getName());
		}
		// 领用位置
		if (ObjectUtils.isNotEmpty(entity.getInlocationId()) && entity.getInlocationId() > 0) {
			PositionVO positionVO = this.positionService.getPositionById(entity.getInlocationId());
			entity.setInlocationName(positionVO.getName());
			entity.setFullLocation(positionVO.getFullLocation());
		}
	}
}
